using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Kaleida.ServiceMonitor.Model.Runtime
{
    public class ReflectionOperationHtmlHelpBuilder
    {
        public static string GetOperationsHtmlHelp(RuntimeEnvironment runtimeEnvironment)
        {
            try
            {
                var summary = new StringBuilder();
                summary.Append("<html>");
                summary.Append("<head><style>");
                summary.Append("h1{font-size:12px;font-family:Sans-Serif;} li{font-size:10px;font-family:Sans-Serif;}");
                summary.Append("</style></head>");

                summary.Append("<body>");
                summary.Append("<h1>Request Types</h1>");
                summary.Append("<ul>");
                summary.Append(String.Concat(runtimeEnvironment.PreparedResponseTypes.Select(BuildOperationHtmlSummary)));
                summary.Append("</ul>");

                summary.Append("<h1>Response Handlers</h1>");
                summary.Append("<ul>");
                summary.Append(String.Concat(runtimeEnvironment.ResponseHandlerTypes.Select(BuildOperationHtmlSummary)));
                summary.Append("</ul>");
                summary.Append("</body></html>");

                return summary.ToString();
            }
            catch (Exception exception)
            {
                return "Error retrieving operation summary: " + exception.Message;
            }
        }

        private static string BuildOperationHtmlSummary(Type type)
        {
            var summary = new StringBuilder();
            var constructors = type.GetOperationConstructors();

            foreach (var constructor in constructors)
            {
                var parameters = constructor.GetParameters();

                var description = GetHtmlDescription(type, parameters);

                summary.Append("<li>");
                summary.AppendFormat("<b>{0}</b> {1}", type.Name.ToDashSeparated(), String.Join(", ", GetHtmlParameterNames(parameters)));
                if (description != "")
                {
                    summary.AppendFormat(" - {0}", description);
                }
                summary.Append("</li>");
            }
            return summary.ToString();
        }

        private static string GetHtmlDescription(Type type, IEnumerable<ParameterInfo> parameters)
        {
            //TODO: use an attribute to contain the operation's general description rather than trying to build a specific instance,
            // using possibly invalid arguments, just to retrieve it's instance-specific description
            try
            {
                var instance = CreateInstance(type, GetHtmlParameterNames(parameters).ToList());
                return (string)instance.GetType().GetProperty("Description").GetValue(instance, new object[0]);
            }
            catch (Exception)
            {
                return "";
            }
        }

        private static object CreateInstance(Type type, IEnumerable<string> arguments)
        {
            try
            {
                return Activator.CreateInstance(type, arguments.Select(i => (object) i).ToArray());
            }
            catch (TargetInvocationException exception)
            {
                throw exception.InnerException;
            }
        }

        private static IEnumerable<string> GetHtmlParameterNames(IEnumerable<ParameterInfo> parameters)
        {
            return parameters.Select(i => "&lt;" + i.Name.ToDashSeparated() + "&gt;");
        }
    }
}